package cn.webestar.scms.gateway.config.filter;

import cn.webestar.scms.commons.SysCode;
import cn.webestar.scms.commons.CommonException;
import cn.webestar.scms.commons.Constant;
import cn.webestar.scms.commons.R;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Slf4j
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private static String errorMsg = "系统异常";

    private static AntPathMatcher matcher = new AntPathMatcher();

    @Autowired
    private ObjectMapper objectMapper;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        final String url = request.getPath().pathWithinApplication().value();
        final String method = exchange.getRequest().getMethod().name();
        log.info("请求METHOD:{},URL:{}", method, url);

        if (isApiUrl(request)) {
            return chain.filter(exchange);
        } else {
            return unauthorizedResponse(exchange, response, new CommonException(SysCode.FORBIDDEN.getCode(), SysCode.FORBIDDEN.getMessage()));
        }

    }

    /**
     * 将 JWT 鉴权失败的消息响应给客户端
     */
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, ServerHttpResponse response, Exception e) {
        R<?> r;
        if(e instanceof CommonException ex){
            r = R.fail(ex.getCode(), ex.getMessage());
        } else {
            r = R.fail(SysCode.FORBIDDEN.getCode(), errorMsg);
        }
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String json = null;
        try {
            json = objectMapper.writeValueAsString(r);
        } catch (JsonProcessingException ex) {
            throw new RuntimeException(ex);
        }
        DataBuffer dataBuffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Flux.just(dataBuffer));
    }

    public static boolean isApiUrl(ServerHttpRequest request) {
        if (Constant.IGNORE_METHOD.equalsIgnoreCase(request.getMethod().name())) {
            return true;
        }
        final String url = request.getPath().pathWithinApplication().value();
        for (String includeUrl : Constant.API_URLS) {
            if (matcher.match(includeUrl, url)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 1;
    }

}
